package ca.eloas.judging.rest.transactions;

import ca.eloas.judging.objectify.PersistenceService;
import ca.eloas.restsupport.utils.CurrentMethod;
import com.googlecode.objectify.Objectify;
import com.googlecode.objectify.Work;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

import javax.inject.Inject;
import java.lang.reflect.Method;

/**
 * @author JP
 */
public class TransactionalInterceptor implements MethodInterceptor {

    private static class ExceptionWrapper extends RuntimeException {
        private static final long serialVersionUID = 1L;

        public ExceptionWrapper(Throwable cause) {
            super(cause);
        }

        /** This makes the cost of using the ExceptionWrapper negligible */
        @Override
        public synchronized Throwable fillInStackTrace() {
            return this;
        }
    }

    @Inject
    private PersistenceService<Objectify> service;

    public Object invoke(final MethodInvocation invocation) throws Throwable {

        Transactional attr = invocation.getStaticPart().getAnnotation(Transactional.class);

        return service.manager().execute(attr.value(), new Work<Object>() {

            public Object run() {
                try {
                    return invocation.proceed();
                }
                catch (RuntimeException ex) { throw ex; }
                catch (Throwable th) { throw new ExceptionWrapper(th); }
            }
        });
    }

}
